/**
 *  Copyright 2011 Marco Berri - marcoberri@gmail.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and limitations under the License.
 **/

package com.conf;

import com.ximpleware.AutoPilot;
import com.ximpleware.NavException;
import com.ximpleware.VTDGen;
import com.ximpleware.VTDNav;
import com.ximpleware.XPathEvalException;
import com.ximpleware.XPathParseException;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.utils.Default;

/**
 *
 * @author Marco Berri marcoberri@gmail.com
 */
public class Main {

    private com.conf.Log log;
    private com.conf.Log cron;
    private com.conf.Proxy proxy;
    private long lm = -1;
    private com.conf.Db db;
    private com.conf.Db stats;
    private com.conf.Mail mail;
    private com.conf.Qrcode qrcode;
    private com.conf.Url url;
    private ArrayList<Map<String, Object>> cron_job;
    /**
     * Root del xml
     */
    public static final String TAG_XML_MAIN = "main";
    /**
     * ramo di cron
     */
    public static final String TAG_XML_CRON = "cron";
    /**
     * job contenuto nel cron
     */
    public static final String TAG_XML_CRON_JOB = "job";
    /**
     * insimeme di properties per il job
     */
    public static final String TAG_XML_CRON_JOB_PROPERTIES = "properties";
    /**
     * script di time per il cron
     */
    public static final String TAG_XML_CRON_JOB_TIME = "time";
    /**
     *
     */
    public static final String TAG_XML_URL = "url";

    /**
     *
     * @param file_conf
     */
    public Main(String file_conf) {
        this.load(file_conf);
    }

    /**
     *
     * @param file_conf
     */
    public void load(String file_conf) {

        File f = new File(file_conf);
        if (!f.exists()) {
            return;
        }

        this.setLm(f.lastModified());

        //analizzo il file di configurazione

        //db

        VTDGen vg = new VTDGen();

        if (vg.parseFile(f.toString(), true)) {


            AutoPilot ap;
            VTDNav vn = vg.getNav();

            try {
                //main
                if (vn.matchElement(TAG_XML_MAIN)) {

                    db = new com.conf.Db();
                    if (vn.toElement(VTDNav.FIRST_CHILD, com.conf.Db.TAG_XML_DB)) {

                        if (vn.toElement(VTDNav.FIRST_CHILD, com.conf.Db.TAG_XML_CLAZZ)) {
                            db.setClazz(vn.toString(vn.getText()));
                        }

                         if (vn.toElement(VTDNav.NEXT_SIBLING, com.conf.Db.TAG_XML_CONN)) {
                            db.setConn(vn.toString(vn.getText()));
                        }

                         if (vn.toElement(VTDNav.NEXT_SIBLING, com.conf.Db.TAG_XML_QUERY)) {
                            if (vn.toElement(VTDNav.FIRST_CHILD, com.conf.Db.TAG_XML_CREATE)) {

                                do {
                                    db.addCreate(vn.toString(vn.getText()));
                                } while (vn.toElement(VTDNav.NEXT_SIBLING, com.conf.Db.TAG_XML_CREATE));
                            }
                        }

                    }//if()

                    stats = new com.conf.Db();
                    vn.toElement(VTDNav.ROOT);
                    vn.matchElement(TAG_XML_MAIN);

                    if (vn.toElement(VTDNav.FIRST_CHILD, com.conf.Db.TAG_XML_STATS)) {

                        if (vn.toElement(VTDNav.FIRST_CHILD, com.conf.Db.TAG_XML_CLAZZ)) {
                            stats.setClazz(vn.toString(vn.getText()));
                        }

                         if (vn.toElement(VTDNav.NEXT_SIBLING, com.conf.Db.TAG_XML_CONN)) {
                            stats.setConn(vn.toString(vn.getText()));
                        }

                         if (vn.toElement(VTDNav.NEXT_SIBLING, com.conf.Db.TAG_XML_QUERY)) {


                            if (vn.toElement(VTDNav.FIRST_CHILD, com.conf.Db.TAG_XML_CREATE)) {

                                do {
                                    stats.addCreate(vn.toString(vn.getText()));
                                } while (vn.toElement(VTDNav.NEXT_SIBLING, com.conf.Db.TAG_XML_CREATE));
                            }
                        }

                         if (vn.toElement(VTDNav.NEXT_SIBLING, com.conf.Db.TAG_XML_KEY)) {
                            stats.setKey(vn.toString(vn.getText()));
                        }

                    }//if()




                    //QRcode
                    qrcode = new com.conf.Qrcode();
                    ap = getAp(vn, "/" + TAG_XML_MAIN + "/" + Qrcode.TAG_XML_QRCODE + "/*");
                    int r = 0;
                    while ((r = ap.evalXPath()) != -1) {

                        if (vn.toString(r).equals(Qrcode.TAG_XML_QRCODE_URL)) {
                            qrcode.setUrl(vn.toString(vn.getText()));
                        }

                         if (vn.toString(r).equals(Qrcode.TAG_XML_QRCODE_DIM)) {
                            qrcode.setDim(vn.toString(vn.getText()));
                        }

                         if (vn.toString(r).equals(Qrcode.TAG_XML_QRCODE_STORAGE)) {
                            qrcode.setStorage(vn.toString(vn.getText()));
                        }

                    }

                    //LOG
                    log = this.getLogBlock(vn, "/" + TAG_XML_MAIN + "/" + Log.TAG_XML_LOG + "/*");
                    if(log == null){
                        System.out.println("Errore nei cercare i parametri del " + "/" + TAG_XML_MAIN + "/" + Log.TAG_XML_LOG + "/*");
                    }

                    //Proxy
                    proxy = new com.conf.Proxy();
                    ap = getAp(vn, "/" + TAG_XML_MAIN + "/" + Proxy.TAG_XML_PROXY + "/*");

                    r = 0;
                    while ((r = ap.evalXPath()) != -1) {

                        if (vn.toString(r).equals(Proxy.TAG_XML_URL)) {
                            proxy.setUrl(vn.toString(vn.getText()));
                        }

                         if (vn.toString(r).equals(Proxy.TAG_XML_TO)) {
                            proxy.setTo(vn.toString(vn.getText()));
                        }

                         if (vn.toString(r).equals(Proxy.TAG_XML_DOMAIN)) {
                            proxy.setDomain(vn.toString(vn.getText()));
                        }

                    }

                    //mail
                    mail = new com.conf.Mail();
                    ap = getAp(vn, "/" + TAG_XML_MAIN + "/" + Mail.TAG_XML_MAIL + "/*");
                    r = 0;
                    while ((r = ap.evalXPath()) != -1) {

                        if (vn.toString(r).equals(Mail.TAG_XML_MAIL_HOSTNAME)) {
                            mail.setHostname(vn.toString(vn.getText()));
                        }

                         if (vn.toString(r).equals(Mail.TAG_XML_MAIL_USERNAME)) {
                            mail.setUsername(vn.toString(vn.getText()));
                        }

                         if (vn.toString(r).equals(Mail.TAG_XML_MAIL_PASSWORD)) {
                            mail.setPassword(vn.toString(vn.getText()));
                        }

                         if (vn.toString(r).equals(Mail.TAG_XML_MAIL_PORT)) {
                            mail.setPort(Default.toInt(vn.toString(vn.getText()), 25));
                        }

                    }


                    //URL
                    url = new com.conf.Url();
                    ap = getAp(vn, "/" + TAG_XML_MAIN + "/" + TAG_XML_URL + "/*");
                    r = 0;
                    while ((r = ap.evalXPath()) != -1) {


                        if (vn.toString(r).equals(Url.TAG_XML_URL_BEST_BEFORE)) {
                            url.setBest_before(vn.toString(vn.getText()));
                        }

                         if (vn.toString(r).equals(Url.TAG_XML_URL_CHARSET)) {
                            url.setCharset(vn.toString(vn.getText()));
                        }
                    }


                    //cron job
                    ap = getAp(vn, "/" + TAG_XML_MAIN + "/" + TAG_XML_CRON + "/" + TAG_XML_CRON_JOB);
                    r = 0;
                    HashMap<String, Object> cron_map = new HashMap<String, Object>();

                    if (this.cron_job == null) {
                        this.cron_job = new ArrayList<Map<String, Object>>();
                    }

                    //scorro i job
                    while ((r = ap.evalXPath()) != -1) {

                        cron_map = new HashMap<String, Object>();

                        //entro nel job
                        VTDNav vnjob = vn.cloneNav();

                        if (vnjob.toElement(VTDNav.FC)) {

                            do {
                                if (vnjob.toString(vnjob.getCurrentIndex()).equals(TAG_XML_CRON_JOB_PROPERTIES)) {
                                    VTDNav vnjob_properties = vnjob.cloneNav();
                                    HashMap<String, String> prop = new HashMap<String, String>();
                                    if (vnjob_properties.toElement(VTDNav.FC)) {
                                        do {
                                            prop.put(vnjob_properties.toString(vnjob_properties.getCurrentIndex()), vnjob_properties.toString(vnjob_properties.getText()));
                                        } while (vnjob_properties.toElement(VTDNav.NEXT_SIBLING));
                                        cron_map.put(TAG_XML_CRON_JOB_PROPERTIES, prop);
                                    }

                                } else {
                                    cron_map.put(vnjob.toString(vnjob.getCurrentIndex()), vnjob.toString(vnjob.getText()));
                                }
                            } while (vnjob.toElement(VTDNav.NEXT_SIBLING));

                        }
                        this.cron_job.add(cron_map);
                    }

                    //log del cron
                    cron = this.getLogBlock(vn, "/" + TAG_XML_MAIN + "/" + TAG_XML_CRON + "/" + Log.TAG_XML_LOG + "/*");
                    if(cron == null){
                        System.out.println("Errore nei cercare i parametri del " + "/" + TAG_XML_MAIN + "/" + TAG_XML_CRON + "/" + Log.TAG_XML_LOG + "/*");
                    }


                }//if()

            } catch (NavException ex) {
                System.out.println(ex.getMessage());
            } catch (XPathEvalException ex) {
                System.out.println(ex.getMessage());
            }

        }

    }

    private AutoPilot getAp(VTDNav vn, String path) {

        try {
            vn.toElement(VTDNav.ROOT);
            vn.matchElement(TAG_XML_MAIN);
            AutoPilot ap = new AutoPilot(vn);
            ap.selectXPath(path);
            return ap;
        } catch (XPathParseException ex) {
            System.out.println(ex.getMessage());
            return null;
        } catch (NavException ex) {
            System.out.println(ex.getMessage());
            return null;
        }

    }

    private com.conf.Log getLogBlock(VTDNav vn, String xpath) {

        try {
            com.conf.Log l = new com.conf.Log();
            vn.toElement(VTDNav.ROOT);
            vn.matchElement(TAG_XML_MAIN);
            AutoPilot ap = new AutoPilot(vn);
            ap.selectXPath(xpath);
            int r = 0;
            while ((r = ap.evalXPath()) != -1) {
                if (vn.toString(r).equals(Log.TAG_XML_LOG_FILENAME)) {
                    l.setFilename(vn.toString(vn.getText()));
                }
                 if (vn.toString(r).equals(Log.TAG_XML_LOG_PATH)) {
                    l.setPath(vn.toString(vn.getText()));
                }
                 if (vn.toString(r).equals(Log.TAG_XML_LOG_ROLLING)) {
                    l.setRolling(vn.toString(vn.getText()));
                }
                 if (vn.toString(r).equals(Log.TAG_XML_LOG_DEBUG)) {
                    l.setDebug(Default.toBoolean(vn.toString(vn.getText()), l.isDebug()));
                }
                 if (vn.toString(r).equals(Log.TAG_XML_LOG_FATAL_MAIL)) {
                    l.setFatal_mail(Default.toBoolean(vn.toString(vn.getText()), l.isFatal_mail()));
                }
            } //if()

            return l;

        } catch (XPathEvalException ex) {
            System.out.println(ex);
        } catch (XPathParseException ex) {
            System.out.println(ex);
        } catch (NavException ex) {
            System.out.println(ex);
        }

        return null;
    }

    /**
     *
     * @param file_conf
     * @return true se ha verificaTO che il file di conf è stato modificiato
     */
    public boolean reload_if_changed(String file_conf) {

        File f = new File(file_conf);

        if (f.lastModified() > this.getLm()) {
            this.load(file_conf);

            return true;
        }

        return false;
    }

    /**
     * @return the lm
     */
    public long getLm() {
        return lm;
    }

    /**
     * @param lm the lm to set
     */
    private void setLm(long lm) {
        this.lm = lm;
    }

    /**
     * @return the cron_clazz
     */
    public List<Map<String, Object>> getCron() {
        return this.cron_job;
    }

    /**
     *
     * @return
     */
    public com.conf.Log getLog() {
        return this.log;
    }

    /**
     *
     * @return
     */
    public com.conf.Log getLogCron() {
        return this.cron;
    }

    /**
     *
     * @return
     */
    public com.conf.Proxy getProxy() {
        return this.proxy;
    }

    /**
     *
     * @return
     */
    public com.conf.Db getDb() {
        return this.db;
    }

    /**
     *
     * @return
     */
    public com.conf.Db getStats() {
        return this.stats;
    }

    /**
     *
     * @return
     */
    public com.conf.Mail getMail() {
        return this.mail;
    }

    /**
     *
     * @return
     */
    public com.conf.Qrcode getQrcode() {
        return this.qrcode;
    }

    /**
     * 
     * @return
     */
    public com.conf.Url getUrl() {
        return this.url;
    }

    /**
     *
     * @return rappresentazion del contenuto delle conf
     */
    @Override
    public String toString() {

        //andare poi via di reflection
        return "\nlog:" + log
                + "\ncron:" + cron
                + "\nlm:" + lm
                + "\ndb:" + db
                + "\nstats:" + stats
                + "\nqrcode:" + qrcode
                + "\ncron_job:" + cron_job
                + "\nproxy:" + proxy
                + "\nmail:" + mail
                + "\nurl:" + url;

    }
}
